home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 050 / madtrb10.arc / GRAPH.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1985-12-16  |  35.8 KB  |  704 lines

  1. Program GraphTheory;
  2.  
  3. { *************************************************************************** }
  4. { *                                                                         * }
  5. { *                        GRAPH THEORY PROGRAM                             * }
  6. { *                             Program #2                                  * }
  7. { *                                                                         * }
  8. { *                     Class: CS 367     Section: 4                        * }
  9. { *                         Instructor: Wiegand                             * }
  10. { *                                                                         * }
  11. { *                       Written by Chris Maeder                           * }
  12. { *                Edited and Compiled using Turbo Pascal                   * }
  13. { *                            on an IBM PC                                 * }
  14. { *                                                                         * }
  15. { *   DEFINITION:                                                           * }
  16. { *        A graph can be thought of as a two dimensional structure         * }
  17. { *        which consists of nodes (or vertices) connected by a set of      * }
  18. { *        edges (or arcs).                                                 * }
  19. { *                                                                         * }
  20. { *                         o----------o                                    * }
  21. { *                          edge^     |                                    * }
  22. { *                                    |                                    * }
  23. { *                                    |                                    * }
  24. { *                                    |                                    * }
  25. { *                                    |                                    * }
  26. { *                                    o------------o                       * }
  27. { *                                   /             ^node                   * }
  28. { *                                 /                                       * }
  29. { *                               /                                         * }
  30. { *                             /                                           * }
  31. { *                           o                                             * }
  32. { *                                                                         * }
  33. { *        This graph structure can be represented in computer memory       * }
  34. { *        as a two dimensional array (see Procedure LinkMatrixModule).     * }
  35. { *        By performing a sequential union test for each element in the    * }
  36. { *        matrix, we are then able to determine the minimum pathlength     * }
  37. { *        between two nodes.                                               * }
  38. { *                                                                         * }
  39. { *   PURPOSE:                                                              * }
  40. { *        1. Print report heading.                                         * }
  41. { *        2. Read input data file.                                         * }
  42. { *        3. Echo print the input data file.                               * }
  43. { *        4. Check that the linked nodes and the node queries are          * }
  44. { *           contained in the initial node list.  Print an error           * }
  45. { *           message if any discrepencies are found.                       * }
  46. { *        5. Using a boolean adjacency matrix, determine minimum           * }
  47. { *           pathlengths between query nodes.                              * }
  48. { *        6. Print pathlength results.                                     * }
  49. { *                                                                         * }
  50. { *   INPUT:                                                                * }
  51. { *        1. Node data that is stored on a disk file. For specification    * }
  52. { *           of input data see Procedure InputModule.                      * }
  53. { *                                                                         * }
  54. { *   OUTPUT:                                                               * }
  55. { *        1. Print output heading                                          * }
  56. { *        2. Echo print the input data file as it is read in               * }
  57. { *           a. Order                                                      * }
  58. { *              i.   Initial list of nodes                                 * }
  59. { *              ii.  List of linked nodes                                  * }
  60. { *              iii. List of pathlenth queries                             * }
  61. { *           b. Format                                                     * }
  62. { *              i.   Use list identifier headers                           * }
  63. { *              ii.  Print error message for any nodes not contained       * }
  64. { *                   in the initial node list                              * }
  65. { *        3. Print minimum pathlength results                              * }
  66. { *           a. Identify both of the query's nodes                         * }
  67. { *           b. State the minimum pathlength                               * }
  68. { *           c. Identify any query nodes that have no path between         * }
  69. { *              each other.                                                * }
  70. { *                                                                         * }
  71. { *   ALGORITHM:                                                            * }
  72. { *        See Procedure PathLengthModule                                   * }
  73. { *                                                                         * }
  74. { *************************************************************************** }
  75.  
  76. Const
  77.   MAX_NODES=15;                              { maximum number of independant nodes }
  78.   MAX_STRING_SIZE=24;
  79.   NODE_LIST_MKR='ZZZ';                       { a marker delineating the the initial node list and the  linked node list }
  80.   NODE_EDGE_MKR='ZZZ ZZZ';                   { a marker delineating the linked node list and the query list }
  81.   FILE_NAME='Graph.Fil';
  82.   DEBUG_INPUT_MODULE=False;                  { a toggle used for debugging the input module }
  83.   DEBUG_LINK_MODULE=False;                   { a toggle used for debugging the link module }
  84.   DEBUG_PATHLENGTH_MODULE=False;             { a toggle used for debugging the pathlength module }
  85.   L_PRINT=False;                             { a boolean used to redirect output to the printer }
  86.  
  87. Type
  88.   NodeEntry=String[MAX_STRING_SIZE];
  89.   AdjacencyMatrix=Array[1..MAX_NODES,1..MAX_NODES] Of Boolean;
  90.   Index=Array[1..MAX_NODES] Of NodeEntry;    { a index list used to store file entries }
  91.   NodeRange=1..MAX_NODES;
  92.   QueryRecord=
  93.     Record
  94.       QueryNode1:String[12];                 { string used to store query node 1 }
  95.       CorrespondingInitialNode1:NodeRange;   { linked list that links the query nodes to the initial nodes }
  96.       QueryNode2:String[12];                 { string used to store query node 1 }
  97.       CorrespondingInitialNode2:NodeRange;   { linked list that links the query nodes to the initial nodes }
  98.       QueryPathLength:0..MAX_NODES;          { used to store the computed pathlength for the query entry }
  99.     End; { QueryRecord }
  100.  
  101. Var
  102.   InitialAdjacencyMatrix:AdjacencyMatrix;    { this adjacency matrix stores all the edges between adjacent nodes }
  103.   Nodes:Index;                               { this is an index of all nodes that tells us what are the proper
  104.                                                rows and cols of the adjacency matrix}
  105.   EdgedNodes:Index;                          { this a list of edged nodes }
  106.   Query:Array[1..MAX_NODES] Of QueryRecord;  { this is a query list }
  107.   MaxNumOfNodes:Integer;                     { total number of nodes }
  108.   MaxNumOfEdgedNodes:Integer;                { total number of adjacent nodes }
  109.   MaxNumOfQueries:Integer;                   { total number of queries }
  110.   HoldPtr:Integer;                           { a temporary pointer used in the re-directing of output from the
  111.                                                screen to the printer }
  112.  
  113.  
  114.  
  115. Procedure InitializeAdjacencyMatrix(Var AdjacencyMatrixName:AdjacencyMatrix);
  116.  
  117. { This procedure initializes the passed adjacency matrix so that all the elements within the adjacency matrix
  118.   are set to False.  This corresponds to no single edge occuring between adjacency matrix nodes. }
  119.  
  120. Var
  121.   Row,Col:Integer;
  122.  
  123. Begin   { InitializeAdjacencyMatrix }
  124.   For Row:=1 To MAX_NODES Do
  125.     For Col:=1 To MAX_NODES Do
  126.       AdjacencyMatrixName[Row,Col]:=False;
  127. End;    { InitializeAdjacencyMatrix }
  128.  
  129.  
  130.  
  131. Function FirstNodeEntry(IndexEntry:NodeEntry):NodeEntry;
  132.  
  133. { This function is passed an index entry which contains the names of two nodes in the given graph.
  134.   These node names are seperated by a single blank space in the index entry.  This function picks off
  135.   the first node name and passes this node name back. }
  136.  
  137. Begin   { FirstNodeEntry }
  138.   FirstNodeEntry:=Copy(IndexEntry,1,(Pos(' ',IndexEntry)-1));
  139. End;    { FirstNodeEntry }
  140.  
  141.  
  142.  
  143. Function SecondNodeEntry(IndexEntry:NodeEntry):NodeEntry;
  144.  
  145. { This function is passed an index entry which contains the names of two nodes in the given graph.
  146.   These node names are seperated by a single blank space in the index entry.  This function picks off
  147.   the second node name and passes this node name back. }
  148.  
  149. Begin   { SecondNodeEntry }
  150.   SecondNodeEntry:=Copy(IndexEntry,(Pos(' ',IndexEntry)+1),(Length(IndexEntry)-Pos(' ',IndexEntry)));
  151. End;    { SecondNodeEntry }
  152.  
  153.  
  154.  
  155. Procedure PrintHeading;
  156.  
  157. { This procedure prints a heading for the output. }
  158.  
  159. Begin   { PrintHeading }
  160.   WriteLn;
  161.   WriteLn('GRAPH THEORY DEMONSTRATION PROGRAM');
  162.   WriteLn;
  163.   WriteLn;
  164. End;    { PrintHeading }
  165.  
  166.  
  167.  
  168. Procedure PrintAdjacencyMatrix(AdjacencyMatrixName:AdjacencyMatrix);
  169.  
  170. { This procedure prints out the elements of the passed adjacency matrix. }
  171.  
  172. Var
  173.   Row,Col:Integer;
  174.  
  175. Begin   { PrintAdjacencyMatrix }
  176.   WriteLn;
  177.   WriteLn('Row   Column');
  178.   WriteLn;
  179.   Write('    ');
  180.   For Col:=1 To MaxNumOfNodes Do             { print out header of column numbers }
  181.     Write(Col,'   ');
  182.   For Row:=1 To MaxNumOfNodes Do             { routine prints out matrix entries }
  183.     Begin
  184.       WriteLn;
  185.       Write(Row,'   ');                      { print out row number }
  186.       For Col:=1 To MaxNumOfNodes Do
  187.         If AdjacencyMatrixName[Row,Col]=True Then
  188.           Write('T   ')
  189.         Else
  190.           Write('F   ');
  191.     End; { For Row }
  192.   WriteLn;
  193. End;    { PrintAdjacencyMatrix }
  194.  
  195.  
  196.  
  197. Procedure InputModule;
  198.  
  199. { *************************************************************************** }
  200. { *                                                                         * }
  201. { *   This module controls the reading of entries out of the file named     * }
  202. { *   above and stores the entries into their proper indexes.               * }
  203. { *                                                                         * }
  204. { *   The input file data is organized as follows:                          * }
  205. { *                                                                         * }
  206. { *     A list of Node names                   Node_Name_1                  * }
  207. { *     that exist on the graph                Node_Name_2                  * }
  208. { *                                                .                        * }
  209. { *                                                .                        * }
  210. { *                                            Node_Name_N                  * }
  211. { *                                                                         * }
  212. { *     A marker used in seperating the data   ZZZ                          * }
  213. { *                                                                         * }
  214. { *     A list of node name pairs              Node_Name Node_Name          * }
  215. { *     that are adjacent to                   Node_Name Node_Name          * }
  216. { *     each other                                 .                        * }
  217. { *                                                .                        * }
  218. { *                                            Node_Name Node_Name          * }
  219. { *                                                                         * }
  220. { *     A marker used in seperating the data   ZZZ ZZZ                      * }
  221. { *                                                                         * }
  222. { *     A query list of node name pairs        Node_Name Node_Name          * }
  223. { *     This program is to determine           Node_Name Node_Name          * }
  224. { *     The path length between the pairs          .                        * }
  225. { *                                                .                        * }
  226. { *                                            Node_Name Node_Name          * }
  227. { *                                                                         * }
  228. { *************************************************************************** }
  229.  
  230. Var
  231.   FileEntry:NodeEntry;
  232.   AdjacencyMatrixFile:Text;                  { text file }
  233.  
  234.  
  235.  
  236.     Procedure PrintIllegalEntry(Entry:NodeEntry);
  237.  
  238.     { This procedure prints out an error message to the user that the current index entry contains at least one node name
  239.       that does not correspond to any of the node names that were initially read into the node name list. }
  240.  
  241.     Begin   { PrintIllegalEntry }
  242.       WriteLn;
  243.       WriteLn('   The following data entry was found to have at least one node name ');
  244.       WriteLn('   that was not found in the initial data list.');
  245.       WriteLn;
  246.       WriteLn('          Illegal Data Entry= ',Entry);
  247.       WriteLn;
  248.     End;    { PrintIllegalEntry }
  249.  
  250.  
  251.  
  252.     Function LegalEntry(IndexEntry:NodeEntry):Boolean;
  253.  
  254.     { The passed index entry contains the names of two nodes.  This function determines if
  255.       the two names are 'Legal', that is, both names are contained in the previously given
  256.       data set of node names. }
  257.  
  258.     Var
  259.       NodeOne,NodeTwo:NodeEntry;             { string variables used to retain the individual node names that
  260.                                                are contained in the index array. }
  261.       IndexRow:Integer;
  262.       NodeOneLegal,NodeTwoLegal:Boolean;     { boolean flag that is used to tell if individual node entry is legal }
  263.  
  264.     Begin   { LegalEntry }
  265.       NodeOneLegal:=False;                   { initialize boolean flag }
  266.       NodeTwoLegal:=False;                   { initialize boolean flag }
  267.       NodeOne:=FirstNodeEntry(IndexEntry);
  268.       NodeTwo:=SecondNodeEntry(IndexEntry);
  269.       For IndexRow:=1 To MaxNumOfNodes Do
  270.         Begin
  271.           If NodeOne=Nodes[IndexRow] Then
  272.             NodeOneLegal:=True;
  273.           If NodeTwo=Nodes[IndexRow] Then
  274.             NodeTwoLegal:=True;
  275.         End; { For IndexRow }
  276.       LegalEntry:=(NodeOneLegal And NodeTwoLegal And (NodeOne<>NodeTwo)) Or (NodeOne='ZZZ');
  277.     End;    { LegalEntry }
  278.  
  279.  
  280.  
  281.     Procedure InsertLegalEntry(QueryEntry:NodeEntry);
  282.  
  283.     { This procedure places the legal query into the query record so that the two node names are seperated
  284.       and a linked list corresponding to the query node and initial node is established.  This allows us to
  285.       see if an adjacency has been established later on. }
  286.  
  287.     Var
  288.       IndexRow:Integer;
  289.  
  290.     Begin   { InsertLegalEntry }
  291.       With Query[MaxNumOfQueries] Do
  292.         Begin
  293.           QueryNode1:=FirstNodeEntry(QueryEntry);    { insert first query name into query record }
  294.           QueryNode2:=SecondNodeEntry(QueryEntry);   { insert second query name into query record }
  295.           For IndexRow:=1 To MaxNumOfNodes Do        { Routine links the query node names with the initial node names }
  296.             Begin                                    { with an index value.  This allows us to easily acess the }
  297.               If QueryNode1=Nodes[IndexRow] Then     { particular element of the transformed matrix to see if adjacency }
  298.                 CorrespondingInitialNode1:=IndexRow; { has just occured. }
  299.               If QueryNode2=Nodes[IndexRow] Then
  300.                 CorrespondingInitialNode2:=IndexRow;
  301.             End; { For IndexRow }
  302.           QueryPathLength:=0;                        { Initialize query pathlength. A '0' denotes no path yet established. }
  303.         End; { With Query }
  304.     End;    { InsertLegalEntry }
  305.  
  306.  
  307.  
  308. Begin   { InputModule }
  309.   If DEBUG_INPUT_MODULE Then
  310.     Begin
  311.       WriteLn;
  312.       WriteLn('***INPUT MODULE***');
  313.     End;
  314.   MaxNumOfNodes:=0;
  315.   MaxNumOfEdgedNodes:=0;
  316.   MaxNumOfQueries:=0;
  317.   Assign(AdjacencyMatrixFile,FILE_NAME);     { assign to a disk file }
  318.   Reset(AdjacencyMatrixFile);                { open the file for reading }
  319.   WriteLn;
  320.   WriteLn;
  321.   WriteLn('INITIAL LIST OF NODES:');
  322.   WriteLn;
  323.   WriteLn;
  324.   Repeat                                     { read in the list of nodes }
  325.     ReadLn(AdjacencyMatrixFile,FileEntry);   { read node entry out of file }
  326.     If FileEntry<>NODE_LIST_MKR Then
  327.       Begin
  328.         MaxNumOfNodes:=MaxNumOfNodes+1;
  329.         Nodes[MaxNumOfNodes]:=FileEntry;
  330.         WriteLn('   ',FileEntry);            { echo out node entry }
  331.       End; { If FileEntry }
  332.   Until FileEntry=NODE_LIST_MKR;
  333.   WriteLn;
  334.   WriteLn;
  335.   WriteLn('LIST OF LINKED NODES:');
  336.   WriteLn;
  337.   WriteLn;
  338.   Repeat                                     { read in list of edged nodes }
  339.     ReadLn(AdjacencyMatrixFile,FileEntry);   { read linked node entry out of file }
  340.     If LegalEntry(FileEntry) Then            { determine if the file entry's names are contained in the initial node list}
  341.       Begin
  342.         If FileEntry<>NODE_EDGE_MKR Then
  343.           Begin
  344.             MaxNumOfEdgedNodes:=MaxNumOfEdgedNodes+1;
  345.             EdgedNodes[MaxNumOfEdgedNodes]:=FileEntry;
  346.             WriteLn('   ',FileEntry);        { echo out legal linked node entry }
  347.           End; { If FileEntry }
  348.       End
  349.     Else
  350.       PrintIllegalEntry(FileEntry);
  351.   Until FileEntry=NODE_EDGE_MKR;
  352.   WriteLn;
  353.   WriteLn;
  354.   WriteLn('LIST OF PATH LENGTH QUERIES:');
  355.   WriteLn;
  356.   WriteLn;
  357.   Repeat                                     { read in list of queires }
  358.     ReadLn(AdjacencyMatrixFile,FileEntry);   { read query entry out of file }
  359.     If LegalEntry(FileEntry) Then            { determine if the file entry's names are contained in the initial node list}
  360.       Begin
  361.         MaxNumOfQueries:=MaxNumOfQueries+1;
  362.         InsertLegalEntry(FileEntry);
  363.         WriteLn('   ',FileEntry);            { echo out legal query entry }
  364.       End
  365.     Else
  366.       PrintIllegalEntry(FileEntry);
  367.   Until Eof(AdjacencyMatrixFile);
  368.   Close(AdjacencyMatrixFile);                { Close the disk file }
  369.   If DEBUG_INPUT_MODULE Then
  370.     Begin
  371.       WriteLn;WriteLn('InitialAdjacencyMatrix follows:');
  372.       PrintAdjacencyMatrix(InitialAdjacencyMatrix);
  373.     End;
  374. End;    { InputModule }
  375.  
  376.  
  377.  
  378. Procedure LinkMatrixModule;
  379.  
  380. { *************************************************************************** }
  381. { *                                                                         * }
  382. { *    This module sets up the intial adjacency matrix which is called      * }
  383. { *    InitialAdjacencyMatrix.  The elements of this adjacency matrix       * }
  384. { *    correspond to whether there exists a single edge between adjacent    * }
  385. { *    nodes, i.e.                                                          * }
  386. { *                                                                         * }
  387. { *       True (T) in a element denotes that there is an edge of length     * }
  388. { *                one between adjacent nodes.                              * }
  389. { *       False (F) in a element denotes that there is not an edge of one   * }
  390. { *                between nodes.                                           * }
  391. { *                                                                         * }
  392. { *    The rows and columns of the adjacency matrix structure correspond    * }
  393. { *    to the given list of nodes.  The example below uses cities as nodes  * }
  394. { *    of a graph                                                           * }
  395. { *                                                                         * }
  396. { *                              C   M   M                                  * }
  397. { *                              h   a   i                                  * }
  398. { *                              i   d   l                                  * }
  399. { *                              c   i   w                                  * }
  400. { *                              a   s   a                                  * }
  401. { *                              g   o   u                                  * }
  402. { *                              o   n   k                                  * }
  403. { *                                      e                                  * }
  404. { *                                      e                                  * }
  405. { *                                                                         * }
  406. { *                  Chicago     F   F   T                                  * }
  407. { *                                                                         * }
  408. { *                  Madison     F   F   T                                  * }
  409. { *                                                                         * }
  410. { *                  Milwaukee   T   T   F                                  * }
  411. { *                                                                         * }
  412. { *    Note that the major diagonal elements are all false since an         * }
  413. { *    element cannot have an adjacent edge to itself.  Notice also that    * }
  414. { *    all adjacency matrix entries are symmetric about the major           * }
  415. { *    diagonal.  One final note, the InitialAdjacencyMatrix never gets     * }
  416. { *    altered during the run of the program since it is needed in          * }
  417. { *    determining the shortest distance between two nodes for every query. * }
  418. { *                                                                         * }
  419. { *************************************************************************** }
  420.  
  421. Var
  422.   IndexRow:Integer;      { A pointer to the current row of the index EdgedNodes }
  423.   Row,Col:Integer;
  424.   Test:Boolean;
  425.  
  426.  
  427.  
  428.     Function ConnectingEdgeExists(IndexEntry,NodeOne,NodeTwo:NodeEntry):Boolean;
  429.  
  430.     { This function is passed two node names from the given graph which are contained in IndexEntry.  This function is
  431.       used in a sequential manner to determine if adjacency exists for the element corresponding to the edge of the
  432.       nodes of the initial adjacency matrix. }
  433.  
  434.     Begin   { ConnectingEdgeExists }
  435.       If DEBUG_LINK_MODULE Then
  436.         Begin
  437.           WriteLn;
  438.           WriteLn('Function: ConnectingEdgeExists');
  439.           WriteLn;
  440.           WriteLn('  InitialNodesIndex,Node1= ',NodeOne);
  441.           WriteLn('  InitialNodesIndex,Node2= ',NodeTwo);
  442.           WriteLn('  EdgedNodesIndex,Node1=  ',FirstNodeEntry(IndexEntry));
  443.           WriteLn('  EdgedNodesIndex,Node2=  ',SecondNodeEntry(IndexEntry));
  444.           WriteLn;
  445.           If (((NodeOne=FirstNodeEntry(IndexEntry))And
  446.             (NodeTwo=SecondNodeEntry(IndexEntry)))Or
  447.             ((NodeOne=SecondNodeEntry(IndexEntry))And
  448.             (NodeTwo=FirstNodeEntry(IndexEntry)))) Then
  449.               WriteLn('  Connecting Edge Exists')
  450.           Else
  451.             WriteLn('  Connecting Edge Does Not Exist');
  452.         End;
  453.       ConnectingEdgeExists:=(((NodeOne=FirstNodeEntry(IndexEntry))And
  454.         (NodeTwo=SecondNodeEntry(IndexEntry)))Or
  455.         ((NodeOne=SecondNodeEntry(IndexEntry))And
  456.         (NodeTwo=FirstNodeEntry(IndexEntry))));
  457.     End;    { ConnectingEdgeExists }
  458.  
  459.  
  460.  
  461. Begin   { LinkMatrixModule }
  462.   If DEBUG_LINK_MODULE Then
  463.     Begin
  464.       WriteLn;
  465.       WriteLn('***LINK MODULE***');
  466.     End;
  467.   For IndexRow:=1 To MaxNumOfEdgedNodes Do
  468.     For Row:=1 To MaxNumOfNodes Do
  469.       For Col:=1 To MaxNumOfNodes Do
  470.         Begin
  471.           If DEBUG_LINK_MODULE Then
  472.             Begin
  473.               WriteLn;
  474.               WriteLn('  EdgedNodesIndexRow= ',IndexRow);
  475.               WriteLn('  InitialAdjacencyMatrixRow=      ',Row);
  476.               WriteLn('  InitialAdjacencyMatrixCol=      ',Col);
  477.             End;
  478.           If ConnectingEdgeExists(EdgedNodes[IndexRow],Nodes[Row],Nodes[Col]) Then
  479.             InitialAdjacencyMatrix[Row,Col]:=True;
  480.         End; { For Col }
  481.   If DEBUG_LINK_MODULE Then
  482.     Begin
  483.       WriteLn;WriteLn('LinkedInitialAdjacencyMatrix follows:');
  484.       PrintAdjacencyMatrix(InitialAdjacencyMatrix);
  485.     End;
  486. End;    { LinkMatrixModule }
  487.  
  488.  
  489.  
  490. Procedure PathLengthModule;
  491.  
  492. { *************************************************************************** }
  493. { *                                                                         * }
  494. { *   This module controls the procedures used in determining the minimum   * }
  495. { *   path length (distance) between two nodes.  This module gets a list    * }
  496. { *   of path length queries from an array of records.                      * }
  497. { *                                                                         * }
  498. { *   These query nodes are checked with the transformed adjacency matrix   * }
  499. { *   to see if adjacency has occured.  If adjacency has occured then the   * }
  500. { *   pathlength is entered into that query's pathlength record field.      * }
  501. { *   If no adjacency was discovered in that transformation, then the       * }
  502. { *   query pathlength field remains zero (corresponding to no pathlength   * }
  503. { *   found).  The process is then repeated until all the pathlengths are   * }
  504. { *   found or the maximum number of transformations have occured.  The     * }
  505. { *   pathlength results are then printed.                                  * }
  506. { *                                                                         * }
  507. { *   The largest minimum pathlength between two nodes is equal to          * }
  508. { *                                                                         * }
  509. { *                    MaxPathLength=MaxNumOfNodes-1                        * }
  510. { *                                                                         * }
  511. { *   The maximum number of transformations of the adjacency matrix is      * }
  512. { *   equal to                                                              * }
  513. { *                                                                         * }
  514. { *                                 =MaxPathLength-1                        * }
  515. { *                                                                         * }
  516. { *   This is because we initially check for adjacency (pathlength=1)       * }
  517. { *   before any transformations occur.                                     * }
  518. { *                                                                         * }
  519. { *   For adjacency matrix transformation algorithm see Procedure           * }
  520. { *   TransformAdjacencyMatrix.                                             * }
  521. { *                                                                         * }
  522. { *************************************************************************** }
  523.  
  524. Var
  525.   CurrentQuery:Integer;                      { a marker to the current query regord }
  526.   PathLength:Integer;
  527.   TestAdjacencyMatrix:AdjacencyMatrix;       { This matrix undergoes a transformation while determining minimum
  528.                                                path lengths.  This matrix is used to determine the minimum pathlengths
  529.                                                between two nodes.  Minimum pathlength is represented as a boolean 'TRUE'
  530.                                                for the adjacency element corresponding to node1 and node2. }
  531.   ContinueSearch:Boolean;                    { a boolean used to flag that there are still query pathlengths that
  532.                                                have yet to be determined. }
  533.   MaxPathLength:Integer;                     { largest minimum pathlength between two nodes }
  534.  
  535.  
  536.  
  537.     Procedure PrintQueryHeading;
  538.  
  539.     { This procedure prints the output heading for the minimum path length output
  540.       to follow. }
  541.  
  542.     Begin   { PrintQueryHeading }
  543.       WriteLn;
  544.       WriteLn;
  545.       WriteLn('MINIMUM PATH LENGTHS FOLLOW:');
  546.       WriteLn;
  547.       WriteLn;
  548.     End;    { PrintQueryHeading }
  549.  
  550.  
  551.  
  552.     Procedure PrintPathLengthResults;
  553.  
  554.     { This procedure prints out the current query and the minimum path length between the two nodes being quered.
  555.       The pathlength is stored in the Query record field 'QueryPathLength'.  This field can have a value from 0 to
  556.       MAX_PATH_LENGTH.  A zero in the field denotes that no path has yet been established between the two nodes. }
  557.  
  558.     Var
  559.       CurrentQuery:Integer;                  { a marker to the current query record }
  560.  
  561.     Begin   { PrintPathLengthResults }
  562.       WriteLn;
  563.       For CurrentQuery:=1 To MaxNumOfQueries Do
  564.         With Query[CurrentQuery] Do
  565.           If QueryPathLength=0 Then
  566.             WriteLn('   No path exists between ',QueryNode1,' and ',QueryNode2)
  567.           Else
  568.             WriteLn('   The minimum pathlength between ',QueryNode1,' and ',QueryNode2,' is ',QueryPathLength);
  569.     End;   { PrintPathLengthResults }
  570.  
  571.  
  572.  
  573.     Procedure CheckForAdjacency;
  574.  
  575.     { This procedure first determines if adjacency has just occurred for any of the queries from the query list.
  576.       It does this by scanning for adjacency for those elements of the transformed matrix corresponding to the
  577.       query nodes (whose pathlengths have not yet been established).  If adjacency is established in a query element,
  578.       the query pathlength is set equal to the current pathlength.  If all the query's pathlengths have been determined,
  579.       it returns a boolean to tell the calling search routine that all the pathlengths have been determined and
  580.       can now exit the search routine and print results. }
  581.  
  582.     Var
  583.       CurrentQuery:Integer;                  { a marker to the current query record }
  584.       SearchDone:Boolean;                    { a boolean flag used to tell when all the pathlengths for all the
  585.                                                queries have been determined. }
  586.  
  587.     Begin  { ContinueSearch }
  588.       SearchDone:=True;
  589.       For CurrentQuery:=1 To MaxNumOfQueries Do
  590.         With Query[CurrentQuery] Do
  591.           Begin
  592.             If QueryPathLength=0 Then
  593.               If TestAdjacencyMatrix[CorrespondingInitialNode1,CorrespondingInitialNode2]=True Then { test for adjacency }
  594.                 QueryPathLength:=PathLength  { set pathlength for query }
  595.               Else
  596.                 SearchDone:=False;           { still pathlengths that need to be determined }
  597.             If DEBUG_PATHLENGTH_MODULE Then
  598.               Begin
  599.                 WriteLn;
  600.                 WriteLn('Current Query = ',CurrentQuery);
  601.                 WriteLn('PathLength    = ',PathLength);
  602.                 WriteLn('MatrixRow     = ',CorrespondingInitialNode1,'    MatrixCol     = ',CorrespondingInitialNode2);
  603.                 WriteLn('Matrix Value  = ',TestAdjacencyMatrix[CorrespondingInitialNode1,CorrespondingInitialNode2]);
  604.               End;
  605.           End; { With Query }
  606.       ContinueSearch:=Not(SearchDone);       { return boolean }
  607.     End;   { ContinueSearch }
  608.  
  609.  
  610.  
  611.     Procedure TransformTestAdjacencyMatrix;
  612.  
  613.     { This procedure transforms the TestAdjacenyMatrix.  The TestAdjacencyMatrix is the adjacency matrix
  614.       that undergoes transformation.  The InitialAdjacencyMatrix remains as itself, being used as such in
  615.       the matrix transformation routine.
  616.  
  617.       TempAdjacencyMAtrix is used to temporarily store the adjacency matrix as it undergoes transformation.
  618.       This is so that the TestAdjacencyMatris can remain independant as the processproceeds.  After the
  619.       transformation process is completed the TeatAdjacencyMatrix is equated to the TempAdjacencyMatrix.
  620.       Then the TestAdjacencyMAtrix is checked if adjacency has occured for a particular query.
  621.  
  622.       Transformation Algorithm:
  623.            Each element of the TestAdjacencyMatrix must be transformed, one at a time.
  624.            What follows is how the transformation of one of these elements take place.
  625.  
  626.            Using the columns of the InitialAdjacencyMatrix and the rows of the TestAdjacencyMatrix corresponding
  627.            to an elemt of the TestAdjacencyMatrix We will then transform that element.  We use the elements of the
  628.            columns and rows sequentally, checking for union between the two column and row elements.  If any union exists
  629.            then that corresponding element of the TempAdjacencyMatrix is set to true.
  630.  
  631.                                            To n
  632.                 TestAdjacencyMatrix(i,j) =  Or [InitialAdjacencyMatrix(k,i) And TestAdjacencyMatrix(j,l)]
  633.                                            For k,l=1
  634.  
  635.            After the entire transformation is completed then the TestAdjacencyMatrix is equated to the now
  636.            transformed matrix. }
  637.  
  638.     Var
  639.       TempAdjacencyMatrix:AdjacencyMatrix;   { Temporary storage matrix for the matrix undergoing transformation
  640.                                                ( so the old version of the TestAdjacencyMatrix remains independent
  641.                                                of the new version of the TestAdjacencyMatrix as it becomes transformed).
  642.                                                Adjacency is represented as a boolean 'TRUE' for TestAdjacencyMatrix
  643.                                                element corresponding to the two queried nodes. }
  644.       Row:Integer;                           { Row of the TestAdjacencyMatrix being used in the
  645.                                                matrix transformation }
  646.       Col:Integer;                           { Col of the InitialAdjacencyMatrix being used in the
  647.                                                matrix transformation }
  648.       Element:Integer;                       { That particular element in Row or Col that is used in a
  649.                                                sequential manner in the matrix transformation }
  650.  
  651.     Begin   { TransformTestAdjacencyMatrix }
  652.       PathLength:=PathLength+1;              { increment pathlength counter }
  653.       For Row:=1 To MaxNumOfNodes Do
  654.         For Col:=1 To MaxNumOfNodes Do
  655.           Begin
  656.             TempAdjacencyMatrix[Row,Col]:=TestAdjacencyMatrix[Row,1] And InitialAdjacencyMatrix[1,Col];
  657.             For Element:=2 To MaxNumOfNodes Do
  658.               TempAdjacencyMatrix[Row,Col]:=TempAdjacencyMatrix[Row,Col] Or (TestAdjacencyMatrix[Row,Element] And
  659.                                             InitialAdjacencyMatrix[Element,Col]);
  660.           End; { For Col }
  661.       TestAdjacencyMatrix:=TempAdjacencyMatrix;
  662.       If DEBUG_PATHLENGTH_MODULE Then
  663.         Begin
  664.           WriteLn;
  665.           WriteLn('Transformed Matrix # ',PathLength);
  666.           PrintAdjacencyMatrix(TestAdjacencyMatrix);
  667.         End;
  668.     End;    { TransformTestAdjacencyMatrix }
  669.  
  670.  
  671.  
  672. Begin { PathLengthModule }
  673.   If DEBUG_PATHLENGTH_MODULE Then
  674.     Begin
  675.       WriteLn;
  676.       WriteLn('***PATHLENGTH MODULE***');
  677.     End;
  678.   MaxPathLength:=MaxNumOfNodes-1;            { largest minimum pathlength between two nodes }
  679.   PathLength:=1;                             { initialize the pathlength }
  680.   ContinueSearch:=True;                      { initialize boolean flag }
  681.   TestAdjacencyMatrix:=InitialAdjacencyMatrix;
  682.   CheckForAdjacency;
  683.   While ContinueSearch And (PathLength<MaxPathLength) Do { routine to search for query's pathlengths }
  684.     Begin
  685.       TransformTestAdjacencyMatrix;
  686.       CheckForAdjacency;
  687.     End;
  688.   PrintQueryHeading;
  689.   PrintPathLengthResults;
  690. End;  { PathLengthModule }
  691.  
  692.  
  693.  
  694. Begin { Main Program }
  695.   HoldPtr:=ConOutPtr;                        { temporaly store current output device address }
  696.   If L_PRINT Then
  697.     ConOutPtr:=LstOutPtr;                    { re-direct output to the printer }
  698.   InitializeAdjacencyMatrix(InitialAdjacencyMatrix);
  699.   PrintHeading;
  700.   InputModule;
  701.   LinkMatrixModule;
  702.   PathLengthModule;
  703.   ConOutPtr:=HoldPtr;                        { reset output device address }
  704. End.  { Main Program }